Skip to main content

Partner Implementation Guide for Engineers

Comprehensive Report

This document serves as an in-depth guide for integrating a new partner module into the system, focusing on clarity, best practices, and compliance with existing project architecture.


Recap of FNZ Monorepo Communication Layer

Our FNZ monorepo is structured to separate concerns clearly between:

  1. Core (common tooling / shared infrastructure)
  2. Types (shared TypeScript definitions)
  3. Backend (infrastructure not accessible to contractors)
  4. Partner Packages (e.g., @fnz/partner-xyz), where external contractors implement custom logic.

We employ a ZeroMQ-based pub/sub approach with a central ZeroMQ broker (in a Docker container) to decouple each partner’s code from the backend. Communication flows through standardized topics (METHOD_REQUEST, METHOD_REPLY, etc.). Contractors implement the partner side (listening and replying to requests) while the backend initiates requests or processes replies, all via @fnz/core’s MessengerService.


Package Overview

1. @fnz/core

  • Node.js package containing:
    • MessengerService (ZeroMQ pub/sub, correlation-based requests, optional exponential retry).
    • Other shared backend infrastructure.
  • Contractors can import from @fnz/core to utilize the messenger logic (subscribe to request topics, publish replies, etc.).

2. @fnz/types

  • Node.js package containing TypeScript type definitions used across FNZ.
  • Ensures consistent typings for shared models, request/response shapes, etc.

3. @fnz/backend

  • Our private backend (NestJS / Node.js), which contractors do not have direct access to.
  • The backend uses @fnz/core’s MessengerService to send commands to partners and handle replies.
  • Manages system-level logic (e.g., orchestrating high-level flows, storing data in our DB, etc.).

4. @fnz/partner-xyz

  • Your partner package (NestJS or Node.js app) that you, the contractor, develop.
  • Imports @fnz/core for the MessengerService and @fnz/types for any shared type definitions.
  • Responds to commands from the backend, publishes relevant replies, can also initiate commands if your use case demands it.
  • Completely decoupled from @fnz/backend aside from the message flows through the ZeroMQ broker.

Communication Flow via ZeroMQ

We have a central Docker container running a ZeroMQ forwarder (in Python). This forwarder has two main ports:

  • 5555: XSUB (listens for publisher messages)
  • 5556: XPUB (allows subscribers to receive messages)

The MessengerService in @fnz/core is configured with:

  • frontendAddress (e.g., tcp://broker:5555)
  • backendAddress (e.g., tcp://broker:5556)

When @fnz/backend or @fnz/partner-xyz want to send a message:

  • They publish on frontendAddress (port 5555).
  • The broker forwards it along to all subscribers listening on backendAddress (port 5556).

Mermaid Diagram

Below is a high-level diagram illustrating the relationships:


1. Required Packages

You will primarily need the following packages to begin the integration process:

  • @fnz/core: Provides essential system functionalities and utilities.
  • @fnz/types: Includes type definitions for interfaces and data structures.
  • @fnz/partner-***: Specific partner implementation package to handle partner-specific logic.

2. Setting Up a New Partner Module

Step 1: Clone and Rename

  1. Navigate to the @fnz/partner-dummy directory and duplicate it to create a new partner folder, e.g., @fnz/partner-abc.
  2. Inside the new directory, update the package.json file:
    {
    "name": "@fnz/partner-abc",
    ...
    }

Step 2: Add to Workspace

Update the root package.json file by adding your new partner package to the workspaces array.

Step 3: Implement Contract Methods

Start implementing partner-specific logic in /src/payments.payments.service.ts and /src/refunds/refunds.service.ts.

You must implement these contract methods:

  1. initialisePayment()

    • Prepares the payment process for initialization.
    • Sets the payment to initiated state.
  2. createPayment()

    • Creates the payment object and transitions it to either processing or success.
  3. processPaymentWebhook()

    • Handles webhook updates for payments received from the partner.
  4. createRefund()

    • Initiates a partial or complete refund process.
  5. processRefundWebhook()

    • Handles webhook updates related to refunds.

3. Database Integration

To ensure proper functionality, make the following database updates:

  1. Partners Table Add an entry for the new partner in the partners table. There should only be one partner entry per agent.

  2. Payment Methods and Bindings

    • Create new payment methods if required, and store them payment_methods table.
    • Insert these rows using a migration script, saved in the migrations/ folder.

For example:

npx prisma migrate dev --name add-id-payment-methods

4. Testing the Module

Testing ensures the partner module operates as expected. While the service can be plugged into the zeroMQ interface, a HTTP interface is exposed for testing purposes.

Use the HTTP interface for testing.

Step 1: Write Unit Tests

  • Use jest-ts to write tests in the tests/ directory.
  • Mock API calls to isolate and validate module logic.

Step 2: Validate Core Flows

Test these critical workflows:

  1. Payment Initialization and Creation

    • Validate that initialisePayment transitions the payment to initiated.
    • Verify that createPayment transitions the payment to processing or success.
  2. Refund Creation and Webhook Handling

    • Ensure createRefund properly initiates a refund.
    • Confirm processRefundWebhook handles webhook updates correctly.
  3. Payment Webhook Handling

    • Check that processPaymentWebhook processes webhook notifications as expected.

Step 3: Run Tests

Execute the tests with:

npm run test

6. Worked example: Implementing Partner "Doku"

Scenario

"Doku" supports bank transfers and direct debit.

Steps

  1. Understand the Flows Review bank transfer and direct debit flows here.

  2. Sequence Diagram Create a diagram outlining the steps for payment and refund handling.

  3. Clone and Implement Clone the @fnz/partner-dummy directory to @fnz/partner-doku. Implement the required contract methods (initialisePayment, createPayment, etc.) in both the payment and refund services.

    In the .env file, populate the following variables:

    NODE_ENV=development
    DATABASE_URL="postgresql://local:local@localhost:5432/partner-dummy?schema=public"
    PORT=8282
    MESSENGER_SERVICE_ID=partner_dummy_001
    PARTNER_CODE=dummy
  4. Test the Implementation Write unit tests to validate the following:

    • Payment creation and refund flows.
    • Webhook handling.
    • Partial or full refund processing.
    • Payment initialization and completion.
  5. Database Updates

    • Add Doku to the partners table.
    • Create relevant payment methods and bindings.